package com.caigou.security.service;


import com.caigou.bean.bid.entity.BidPrivilege;
import com.caigou.bean.cms.entity.UserPrivilege;
import com.caigou.bean.exam.entity.Users;
import com.caigou.enums.Constant;
import com.caigou.security.entity.JwtUser;
import com.caigou.security.entity.SecurityUser;
import com.caigou.security.utils.JwtTokenUtils;
import com.caigou.service.IUserBaseInfoService;
import com.caigou.service.IUsersService;
import com.caigou.util.RSAUtils;
import com.caigou.util.UUIDUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * Created by echisan on 2018/6/23
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Resource
    private IUsersService usersService;
    @Resource
    private IUserBaseInfoService userBaseInfoService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        // 验证用户名是否正确
        Users userInfo = usersService.findUserByTel(username);
        SecurityUser user = new SecurityUser();
        if (userInfo != null) {
            String uuid = UUIDUtil.getUUID();
            user.setUsername(userInfo.getTel());
            user.setId(userInfo.getId());
            user.setPassword(userInfo.getPassword() + "##" + userInfo.getSalt() + "##" + userInfo.getTel());
            user.setUserId(userInfo.getUserid());
            user.setSalt(userInfo.getSalt());
            //给用户设置权限
            List<UserPrivilege> privileges = usersService.findPrivilegeCodesByUserId(userInfo.getUserid());
            ArrayList<GrantedAuthority> authorities = new ArrayList<>();

            //给用户设置权限
            List<BidPrivilege> bidPrivileges = usersService.findBidPrivilegesByUserId(userInfo.getUserid(), Constant.UNSTRUCTURED_DATA);
            if (!CollectionUtils.isEmpty(bidPrivileges)) {
                bidPrivileges.stream().forEach(privilege -> {
                    authorities.add(new SimpleGrantedAuthority(privilege.getPrivilegeCode()));
                });
            }

            if (!CollectionUtils.isEmpty(privileges)) {
                privileges.forEach(privilege -> {
                    authorities.add(new SimpleGrantedAuthority(privilege.getPrivilegeCode()));
                });
                user.setAuthorities(authorities);
            }
            authorities.add(new SimpleGrantedAuthority("user_login"));
            user.setAuthorities(authorities);
            //由底层实现来查询寻用户信息.并判断密码是否正确
            String token = JwtTokenUtils.createToken(username, userInfo.getUserid(),
                    authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()), true);

            String format = String.format(Constant.TOKEN_PREFIX_KEY, userInfo.getUserid(), uuid);
            try {
                String encodedData = RSAUtils.publicEncrypt(format, RSAUtils.getPublicKey(JwtTokenUtils.PUBLIC_KYE));
                user.setFrontToken(encodedData);
                stringRedisTemplate.opsForValue().set(encodedData, JwtTokenUtils.TOKEN_PREFIX + token,JwtTokenUtils.TOKEN_LIFE_TIME, TimeUnit.HOURS);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                e.printStackTrace();
            }
            return new JwtUser(user);
        }
        //TODO 未知用户需要处理
        return new JwtUser(user);
    }

}
